package utils;

import java.util.Vector;

import utils.math_utils._Matrix;

public class Metrics {

	//Ensures that the target matrix is of the same dimenions as the output
	//matrix
	public static void DIM_AGREEMENT(double [][] targs, double [][] outs){
		if(targs.length != outs.length || targs[0].length != outs[0].length){
			throw new IllegalArgumentException("Target matrix and output" +
					" matrix do not have the same dimensions");
		}
	}
	
	//finds the indices in the target matrix where verbs are possible
	public static Vector<Integer> FindVerbs(double [][] targs){
		Vector<Integer> VerbInds = new Vector<Integer>();
		for(int i = 0; i < targs.length; i++){
			for(int j = 10; j < 22; j++){
				if(targs[i][j] > 0.0){
					VerbInds.add(i);
					break;
				}
			}
		}
		return VerbInds;
	}
	
	public static double AvgCos(double [][] targs, double [][] outs){
		DIM_AGREEMENT(targs, outs);
		double cos = 0.0;
		for(int i = 0; i < outs.length; i++){
		double norms = _Matrix.norm(targs[i])*_Matrix.norm(outs[i]);
		if(norms == 0)
			norms = 0.001;
		cos += _Matrix.dotProduct(outs[i], targs[i])/norms;
		}
		cos = (double) cos/(outs.length);
		return cos;
	}
	
	public static double MaxPrediction(double [][] targs, double [][] outs){
		DIM_AGREEMENT(targs, outs);
		int M = 0;
		for(int i = 0; i < outs.length; i++){
			int Z = _Matrix.MaxIndex(outs[i]);
			if(targs[i][Z] > 0.0){
				M++;
			}
		}
		double MaxP = (double) M/outs.length;
		return MaxP;
	}
	
	public static double VerbAgreement(double [][] targs, double [][] outs){
		DIM_AGREEMENT(targs, outs);
		int Vc;
		int Vw;
		double VCorrect;
		double Vwrong;
		double VA = 0.0;
		Vector<Integer> Verbs = FindVerbs(targs);
		for(Integer I : Verbs){
			VCorrect = 0.0;
			Vwrong = 0.0;
			Vc = 0;
			Vw = 0;
			for(int J = 10; J < 22; J++){
				if(targs[I][J] == 0.0){
					Vw++;
					Vwrong += outs[I][J];
				}
				if(targs[I][J] > 0.0){
					Vc++;
					VCorrect += outs[I][J];
				}
			}
			VCorrect = (double) VCorrect/Vc;
			Vwrong = (double) Vwrong/Vw;
			if(VCorrect > Vwrong){
				VA += 1.0;
			}
		}
		VA = (double) VA/Verbs.size();
		return VA;
	}
	
	public static double [][] ROCurve(double [][] targs, double [][] outs){
		DIM_AGREEMENT(targs, outs);
		double [][] HF = new double [2][200];
		double theta = -1.0;
		for(int k = 0; k < 200; k++){
			int Pos = 0;
			int Neg = 0;
			for(int i  = 0; i < outs.length; i++){
				double TP = 0.0;
				double FP = 0.0;
				int Tcount = 0;
				int Fcount = 0;
				for(int j = 0; j < outs[0].length; j++){
					if(targs[i][j] > 0){
						TP += outs[i][j];
						Tcount++;
					}else{
						FP += outs[i][j];
						Fcount++;
					}
				}
				if(TP/Tcount > theta)
					Pos++;
				if(FP/Fcount > theta)
					Neg++;
			}
			HF[0][k] = (double) Pos/outs.length;
			HF[1][k] = (double) Neg/outs.length;
			theta += 0.02;
		}
		return HF;
	}
	
	public static double AUC(double [][] targs, double [][] outs, String WOI){
		double [][] HF = new double [2][200];
		double theta = -1.0;
		double Count;
		Vector<Integer> Class = new Vector<Integer>();
		if(WOI.matches("Trans") || WOI.matches("Intrans") 
				|| WOI.matches("Optrans")){
			if(WOI.matches("Trans")){
				Class.add(10);
				Class.add(11);
				Class.add(16);
				Class.add(17);
			}else if(WOI.matches("Intrans")){
				Class.add(14);
				Class.add(15);
				Class.add(20);
				Class.add(21);
			}else{
				Class.add(12);
				Class.add(13);
				Class.add(18);
				Class.add(19);
			}
			Count = 4.0;
		}else if(WOI.matches("Who")){
			Class.add(22);
			Count = 1.0;
		}else if(WOI.matches("Noun")){
			for(int i = 0; i < 10; i++)
				Class.add(i);
				Count = 10;
		}else{
			Class.add(23);
			Count = 1.0;
		}
		boolean Bob = true;
		
		int Pos;
		int Neg;
		int False;
		int True;
		double TH;
		double FA;
		for(int k = 0; k < 200; k++){
			Pos = 0;
			Neg = 0;
			True = 0;
			False = 0;
			for(int i = 0; i < targs.length; i++){
				TH = 0.0;
				FA = 0.0;
				for(Integer j : Class){
					if(targs[i][j] > 0.0){
						Bob = true;
						TH += outs[i][j];
					}else{
						FA += outs[i][j];
						Bob = false;
					}
				}
				//System.out.println("TH: " + TH);
				if(Bob){
					True++;
					if((TH/Count) > theta)
						Pos++;
				}else{
					False++;
					if((FA/Count) > theta)
						Neg++;
				}
			}
			HF[0][k] = (double)Pos/True;
			HF[1][k] = (double)Neg/False;
			theta += 0.02;
		}
		double AUC = 0.0;
		double Area = HF[0][0]*HF[1][0]; 
		for(int i = 1; i < HF[1].length; i++){
			if(HF[1][i] - HF[1][i-1] == 0)
				continue;
			else{
				AUC += 0.5*((HF[0][i]+HF[0][i-1])*(HF[1][i-1]-HF[1][i]));
			}
		}
		AUC = AUC/Area;
		return AUC;
	}
	
	public static double [][] VerbDist(double [][] targs, double [][] outs,
			Vector<int []> VerbDists){
		double [] [] Bins = new double[14][2];
		double Va, Vf;
		int Vc;
		int Vfc;
			for(int [] Loc : VerbDists){
				Va = 0.0;
				Vf = 0.0;
				Vc = 0;
				Vfc = 0;
				if(Loc[0] != 0){
				for(int i = 10; i < 22; i++){
					if(targs[Loc[0]-1][i] != 0.0){
						Va += outs[Loc[0]-1][i];
						Vc ++;
					}else{
						Vf += outs[Loc[0]-1][i];
						Vfc++;
					}
				}
				if(Va/Vc > Vf/Vfc){
					Bins[Loc[1]][0] += 1.0;
				}
				Bins[Loc[1]][1] += 1.0;
				}
			}
			for(int k = 0; k < Bins.length; k++){
				if(Bins[k][1] != 0.0)
					Bins[k][0] = Bins[k][0]/Bins[k][1];
				else
					Bins[k][0] = 0.0;
			}
		return Bins;
	}
	
}
